//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//  File:  PDD.c
//  Programmer: Visual.Wei
//  Date: 2007-4-26
//  Description: port from CE drivers
//
#include <windows.h>
#include <oal.h>
#include <s3c2440x.h>
#include "pdd.h"
#include <ipl_core.h>

#define USB_Unlock() _enable_irq()
#define USB_Lock() _disable_irq();
#if 0
#undef DEBUGMSG
#define DEBUGMSG(con,exp) (printk exp)
const char pszFname[]="pdd.cpp";
#else
#undef RETAILMSG
#define RETAILMSG(con,exp) (printk exp)
const char pszFname[]="pdd.cpp";
#endif

typedef DWORD EP0_STATE;
#define   EP0_STATE_IDLE 0
#define   EP0_STATE_IN_DATA_PHASE 1
#define   EP0_STATE_OUT_DATA_PHASE 2

#define IN_TRANSFER  1
#define OUT_TRANSFER 2

#define EP0_STALL_BITS (EP0_SEND_STALL | EP0_SENT_STALL)


typedef struct
{
	DWORD                   dwEndpointNumber;
	DWORD                   dwDirectionAssigned;
	DWORD                   dwPacketSizeAssigned;
	BOOL                    fInitialized;
	DWORD                   dwEndpointType;
	PSTransfer              pTransfer;
}
EP_STATUS,*PEP_STATUS;




#define EP_0_PACKET_SIZE    0x8    // Could also be 16 but they recommend 8

#define ENDPOINT_COUNT  5
#define EP_VALID(x)     ((x) < ENDPOINT_COUNT)
#define DEFAULT_PRIORITY 100

typedef struct CTRL_PDD_CONTEXT
{
	PVOID             pvMddContext;
	DWORD             dwSig;
	BOOL              fRunning;
	BOOL              fSpeedReported;
	BOOL              fRestartIST;
	BOOL              fExitIST;
	BOOL              attachedState;
	BOOL              sendDataEnd;
	EP0_STATE         Ep0State;

	// registry
	DWORD             dwIOBase;
	DWORD             dwSysIntr;
	DWORD             dwIrq;
	DWORD             dwIOLen;
	DWORD             dwISTPriority;

	USB_DEVICE_REQUEST udr;
	EP_STATUS         rgEpStatus[ENDPOINT_COUNT];

	PFN_UFN_MDD_NOTIFY      pfnNotify;
	CEDEVICE_POWER_STATE    cpsCurrent;
}
*PCTRLR_PDD_CONTEXT;

static struct CTRL_PDD_CONTEXT g_pdd;

#define SC2440_SIG '2440' // "SC2440" signature

#define IS_VALID_SC2440_CONTEXT(ptr) \
    ( (ptr != NULL) && (ptr->dwSig == SC2440_SIG) )


#define SET   TRUE
#define CLEAR FALSE


// Retrieve the endpoint status structure.
static PEP_STATUS GetEpStatus(PCTRLR_PDD_CONTEXT pContext,DWORD dwEndpoint
)
{

	PEP_STATUS peps = &pContext->rgEpStatus[dwEndpoint];

	return peps;
}


// Return the irq bit for this endpoint.
static BYTE EpToIrqStatBit(
    DWORD dwEndpoint
)
{
	return (1 << (BYTE)dwEndpoint);
}

/*++
 
Routine Description:
 
Enable the interrupt of an endpoint.
 
Arguments:
 
dwEndpoint - the target endpoint
 
Return Value:
 
None.
 
--*/
static VOID EnableDisableEndpointInterrupt(
    PCTRLR_PDD_CONTEXT  pContext,
    DWORD               dwEndpoint,
    BOOL                fEnable
)
{

	// Disable the Endpoint Interrupt
	BYTE bEpIntReg = rEP_INT_EN_REG;
	BYTE bIrqEnBit = (1 << (BYTE)dwEndpoint);

	if (fEnable)
	{
		bEpIntReg |= bIrqEnBit;
	}
	else
	{
		bEpIntReg &= ~bIrqEnBit;
	}

	rEP_INT_EN_REG=bEpIntReg;


}

static VOID EnableEndpointInterrupt(PCTRLR_PDD_CONTEXT  pContext,DWORD dwEndpoint)
{
	EnableDisableEndpointInterrupt(pContext, dwEndpoint, TRUE);

}

static VOID DisableEndpointInterrupt(PCTRLR_PDD_CONTEXT  pContext,DWORD dwEndpoint)
{
	EnableDisableEndpointInterrupt(pContext, dwEndpoint, FALSE);
}

/*++
 
Routine Description:
 
Clear the interrupt status register index of an endpoint.
 
Arguments:
 
dwEndpoint - the target endpoint
 
Return Value:
 
None.
 
--*/
static
VOID
ClearEndpointInterrupt(
    PCTRLR_PDD_CONTEXT pContext,
    DWORD        dwEndpoint
)
{
	// Clear the Endpoint Interrupt
	BYTE bIntBit = EpToIrqStatBit(dwEndpoint);
	SETFNAME();
	FUNCTION_ENTER_MSG();
	rEP_INT_REG=bIntBit;

	FUNCTION_LEAVE_MSG();
} // _ClearInterrupt



// Reset the device and EP0.
static VOID ResetDevice(PCTRLR_PDD_CONTEXT pContext)
{
	
	rPWR_REG=DISABLE_SUSPEND;	//disable suspend mode

	////EP0 max packit size = 8,clear OUT_PKT_RDY & SETUP_END
	rINDEX_REG=0;
	rMAXP_REG=FIFO_SIZE_8;
	rEP0_CSR=EP0_SERVICED_OUT_PKT_RDY|EP0_SERVICED_SETUP_END;
	pContext->rgEpStatus[0].dwPacketSizeAssigned = 8;
	pContext->rgEpStatus[0].dwEndpointNumber = 0;

	//EP1:max packit size = 64,bulk,IN mode, IN_DMA_INT=masked
	rINDEX_REG=1;
	rMAXP_REG=FIFO_SIZE_64;
	rIN_CSR1_REG=EPI_FIFO_FLUSH|EPI_CDT;
	rIN_CSR2_REG=EPI_MODE_IN|EPI_IN_DMA_INT_MASK|EPI_BULK;
	rOUT_CSR1_REG=EPO_CDT;
	rOUT_CSR2_REG=EPO_BULK|EPO_OUT_DMA_INT_MASK;
	pContext->rgEpStatus[1].dwPacketSizeAssigned = 64;
	pContext->rgEpStatus[1].dwDirectionAssigned = USB_IN_TRANSFER;
	pContext->rgEpStatus[1].dwEndpointNumber = 1;

	//EP2:max packit size = 64,bulk,OUT mode, IN_DMA_INT=masked
	rINDEX_REG=2;
	rMAXP_REG=FIFO_SIZE_64;
	rIN_CSR1_REG=EPI_FIFO_FLUSH|EPI_CDT;
	rIN_CSR2_REG=EPI_MODE_OUT|EPI_IN_DMA_INT_MASK|EPI_BULK;
	rOUT_CSR1_REG=EPO_CDT;
	rOUT_CSR2_REG=EPO_BULK|EPO_OUT_DMA_INT_MASK;
	pContext->rgEpStatus[2].dwPacketSizeAssigned = 64;
	pContext->rgEpStatus[2].dwDirectionAssigned = USB_OUT_TRANSFER;
	pContext->rgEpStatus[2].dwEndpointNumber = 2;

	//EP3:max packit size = 32,OUT mode, IN_DMA_INT=masked
	rINDEX_REG=3;
	rMAXP_REG=FIFO_SIZE_64;
	rIN_CSR1_REG=EPI_FIFO_FLUSH|EPI_CDT;
	rIN_CSR2_REG=EPI_MODE_IN|EPI_IN_DMA_INT_MASK|EPI_BULK;
	rOUT_CSR1_REG=EPO_CDT;
	rOUT_CSR2_REG=EPO_BULK|EPO_OUT_DMA_INT_MASK;
	pContext->rgEpStatus[3].dwPacketSizeAssigned = 64;
	pContext->rgEpStatus[3].dwDirectionAssigned = USB_IN_TRANSFER;
	pContext->rgEpStatus[3].dwEndpointNumber = 3;

	rINDEX_REG=4;
	rMAXP_REG=FIFO_SIZE_64;	//EP4:max packit size = 64
	rIN_CSR1_REG=EPI_FIFO_FLUSH|EPI_CDT;
	rIN_CSR2_REG=EPI_MODE_OUT|EPI_IN_DMA_INT_MASK|EPI_BULK; //OUT mode, IN_DMA_INT=masked
	rOUT_CSR1_REG=EPO_CDT;
	rOUT_CSR2_REG=EPO_BULK|EPO_OUT_DMA_INT_MASK;
	pContext->rgEpStatus[4].dwPacketSizeAssigned = 0;
	pContext->rgEpStatus[4].dwEndpointNumber =4;

	rEP_INT_REG=EP0_INT|EP1_INT|EP2_INT|EP3_INT|EP4_INT;
	rUSB_INT_REG=RESET_INT|SUSPEND_INT|RESUME_INT;
	//Clear all usbd pending bits

	//EP0,1,2,3 & reset interrupt are enabled
	rEP_INT_EN_REG=EP0_INT|EP1_INT|EP2_INT|EP3_INT;
	//rEP_INT_EN_REG=EP0_INT;
	rUSB_INT_EN_REG=RESET_INT;
}


static
VOID
CompleteTransfer(
    PCTRLR_PDD_CONTEXT pContext,
    PEP_STATUS peps,
    DWORD dwUsbError
)
{
	PSTransfer pTransfer = peps->pTransfer;

	peps->pTransfer = NULL;

	pTransfer->dwUsbError = dwUsbError;
	pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_TRANSFER_COMPLETE,
	                    (DWORD) pTransfer);
}





// Read data from an endpoint.
static
BYTE
HandleRx(
    PCTRLR_PDD_CONTEXT       pContext,
    PEP_STATUS peps,
    PBOOL pfCompleted,
    PDWORD pdwStatus
)
{
	BOOL fCompleted = FALSE;
	DWORD dwStatus = ERROR_GEN_FAILURE;
	DWORD dwEndpoint = peps->dwEndpointNumber;
	BYTE bRet = 0;
	PSTransfer pTransfer;
	PBYTE  pbBuffer;
	DWORD cbBuffer;
	DWORD cbFifo;
	DWORD cbRead;
	DWORD cbToRead;
	BYTE bEpIrqStat;
	BYTE outCSR1;

	pTransfer = peps->pTransfer;

	if (pTransfer)
	{
loop:

		pbBuffer =  (PBYTE)pTransfer->pvBuffer + pTransfer->cbTransferred;

		cbBuffer = pTransfer->cbBuffer - pTransfer->cbTransferred;
		rINDEX_REG=dwEndpoint;
		cbFifo = rOUT_FIFO_CNT1_REG;

		// Read from the FIFO
		cbRead = min(cbFifo, cbBuffer);
		cbToRead = cbRead;
		if(dwEndpoint==0)
		{
			while (cbToRead--)
			{
				*pbBuffer++ = rEP0_FIFO;
			}
		}
		else if(dwEndpoint==1)
		{
			while (cbToRead--)
			{
				*pbBuffer++ = rEP1_FIFO;
			}
		}
		else if(dwEndpoint==2)
		{
			while (cbToRead--)
			{
				*pbBuffer++ = rEP2_FIFO;
			}
		}
		else if(dwEndpoint==3)
		{
			while (cbToRead--)
			{
				*pbBuffer++ = rEP3_FIFO;
			}
		}		
		else if(dwEndpoint==4)
		{
			while (cbToRead--)
			{
				*pbBuffer++ = rEP4_FIFO;
			}
		}		
		pTransfer->cbTransferred += cbRead;

		if ( (cbRead < peps->dwPacketSizeAssigned) ||
		        (pTransfer->cbTransferred == pTransfer->cbBuffer) )
		{
			// Short packet or filled buffer. Complete transfer.
			fCompleted = TRUE;
			dwStatus = UFN_NO_ERROR;
		}

		if (dwEndpoint == 0)
		{
			bRet |= SERVICED_OUT_PKY_RDY;

			if (fCompleted)
			{
				bRet |= DATA_END;
				pContext->Ep0State = EP0_STATE_IDLE;
			}
		}
		else
		{
			if((peps->dwEndpointType == USB_ENDPOINT_TYPE_BULK) && (!fCompleted))
			{
				outCSR1 = rOUT_CSR1_REG;

				outCSR1 = outCSR1 & (OUT_SEND_STALL | OUT_SENT_STALL) &
				          ~(OUT_CLR_DATA_TOGGLE) & (~OUT_PACKET_READY);

				rOUT_CSR1_REG=outCSR1;

				outCSR1 = rOUT_CSR1_REG;
				bEpIrqStat = rEP_INT_REG;


				if(outCSR1 & OUT_PACKET_READY)
				{

					if (bEpIrqStat & (1<< dwEndpoint))
					{
						rEP_INT_REG=(1 << dwEndpoint);
					}
					goto  loop;

				}
				else
				{

					bRet |=OUT_PACKET_READY;
				}



			}
		}
		DEBUGMSG(ZONE_RECEIVE, (_T("Rx Ep%x BufSize=%u,Xfrd=%u \r\n"),
		                       dwEndpoint, pTransfer->cbBuffer, pTransfer->cbTransferred));

		if (fCompleted)
		{
			DEBUGMSG(ZONE_RECEIVE, (_T("RxDone Ep%x BuffSize=%u, Xfrd=%u\r\n"),
			                dwEndpoint,pTransfer->cbBuffer, pTransfer->cbTransferred));
		}
	}

	*pfCompleted = fCompleted;
	*pdwStatus = dwStatus;


	return bRet;
}


// Write data to an endpoint.
static
BYTE
HandleTx(
    PCTRLR_PDD_CONTEXT       pContext,
    PEP_STATUS peps,
    BOOL fEnableInterrupts
)
{
	BYTE bRet = 0;
	BOOL fCompleted = FALSE;
	PSTransfer pTransfer = peps->pTransfer;
	DWORD dwStatus = ERROR_GEN_FAILURE;
	DWORD dwEndpoint = peps->dwEndpointNumber;
	PBYTE pbBuffer;
	DWORD cbBuffer;
	DWORD cbWritten;
	DWORD cbToWrite;
	BYTE bRegStatus;

	pTransfer = peps->pTransfer;
	if (pTransfer)
	{

		// Transfer is ready
		pbBuffer = (PBYTE) pTransfer->pvBuffer + pTransfer->cbTransferred;
		cbBuffer = pTransfer->cbBuffer - pTransfer->cbTransferred;

		cbWritten = 0;


		// Min of input byte count and supported size
		cbToWrite = min(cbBuffer, peps->dwPacketSizeAssigned);
		rINDEX_REG=dwEndpoint;
		bRegStatus = rIN_CSR1_REG;

		DEBUGMSG(ZONE_SEND, (_T("Tx EP%u %uB,\r\n"),dwEndpoint, cbToWrite));

		if (dwEndpoint == 0)
		{
			for (cbWritten = 0; cbWritten < cbToWrite; cbWritten++)
				rEP0_FIFO = *pbBuffer++;


			/* We can complete on a packet which is full. We need to wait till
			* next time and generate a zero length packet, so only complete
			* if we're at the end and it is not the max packet size.
			*/
			pTransfer->cbTransferred += cbWritten;
			if (pTransfer->cbTransferred == pTransfer->cbBuffer && pTransfer->pvPddData == 0)
			{
				dwStatus = UFN_NO_ERROR;
				fCompleted = TRUE;
				pContext->Ep0State = EP0_STATE_IDLE;
				bRet |= DATA_END;
			}

			/* Update the register - Set the IPR bit
			and possibly data end*/
			if( (cbWritten > 0) || (pTransfer->cbBuffer == 0) )
			{
				bRet |= EP0_IN_PACKET_RDY;
			}
			// Also set IPR if a 0 byte packet needs to go out.
			else if(pTransfer->pvPddData)
			{
				bRet |= EP0_IN_PACKET_RDY;
				pTransfer->pvPddData = 0;
			}
		}
		else
		{
			// Enable Interrupts before writing to the FIFO. This insures
			// That any interrupts generated because of the write will be
			// "latched"
			if (fEnableInterrupts)
			{
				DEBUGCHK(dwEndpoint != 0);
				EnableEndpointInterrupt(pContext, dwEndpoint);
			}

			// Write to the FIFO directly to send the bytes.
			for (cbWritten = 0; cbWritten < cbToWrite; cbWritten++)
			{
				if(dwEndpoint==1)
					rEP1_FIFO = *pbBuffer++;				
				else if(dwEndpoint==2)
					rEP2_FIFO = *pbBuffer++;
				else if(dwEndpoint==3)
					rEP3_FIFO = *pbBuffer++;
				else if(dwEndpoint==4)
					rEP4_FIFO = *pbBuffer++;	
			}

			// By Placing the check for packet complete here, before
			// cbTransferred is updated, there is a 1 interrupt cycle delay
			// That is complete is not declared until the data has actually
			// been ACKd (TPC set) by the host


			if ( (pTransfer->cbTransferred == pTransfer->cbBuffer) ||
			        (cbWritten == 0) )
			{
				fCompleted = TRUE;
				dwStatus = UFN_NO_ERROR;
				if ( cbWritten == 0 ) //Elt_R05P01_060317B
					bRet |= IN_PACKET_READY;		// woo
			}
			else
			{
				/* Set In Packet Ready , this will Tells the HW the FIFO is
				          ready to be transitted to be sent
				          */
				bRet |= IN_PACKET_READY;
			}
			// Update the Transfered Count
			pTransfer->cbTransferred += cbWritten;
		}

	}
	else
	{
		// It is possible for an interrupt to come in while still in this
		// function for first pass of transfer. If this happens it is possible
		// to complete the transfer and have that interrupt be unnecessary
		// so... just ignore it.
		goto EXIT;
	}


	if (fCompleted)
	{
		// Disable transfer interrupts until another transfer is issued.
		if (peps->dwEndpointNumber != 0)
		{
			DisableEndpointInterrupt(pContext, peps->dwEndpointNumber);
		}


		DEBUGMSG(ZONE_SEND, (_T("Tx Done  Ep%x  Status %u,\r\n"), dwEndpoint, dwStatus));
		CompleteTransfer(pContext, peps, dwStatus);
	}
	else
	{
		DEBUGMSG(ZONE_SEND, (_T("Tx EP%x BfS=%u Xf=%u, "),
		                     dwEndpoint, pTransfer->cbBuffer, pTransfer->cbTransferred));
	}

EXIT:

	return bRet;
}

//Visual debug
static void DBG_SetupReq(PBYTE pbUdr)
{
	RETAILMSG(1, (_T("SET 0x%x %x %x %x %x %x %x %x, "),pbUdr[0],pbUdr[1],pbUdr[2],pbUdr[3],
									pbUdr[4],pbUdr[5],pbUdr[6],pbUdr[7]));
}

static VOID HandleEndpoint0Event(PCTRLR_PDD_CONTEXT  pContext)
{
	BYTE bEP0IrqStatus;
	BYTE bEp0CsrToWrite;
	PSTransfer pTransfer;
	BOOL fSendUdr ;
	DWORD cbFifo ;
	BOOL fCompleted;
	DWORD dwStatus;
	DWORD cbOutFifo;
	PBYTE pbUdr;
	DWORD cbBytesRemaining;
	BOOL bHandleTx;
	PEP_STATUS peps;

	peps = GetEpStatus(pContext, 0);

	//Clear Endpoint Interrupt
	rEP_INT_REG=EP0_INT;

	rINDEX_REG=0;
	bEP0IrqStatus = rEP0_CSR;

	// Write 0 to SEND_STALL and SENT_STALL to clear them, so we need to
	// leave them unchanged by default.
	bEp0CsrToWrite = 0;

	if (bEP0IrqStatus & SETUP_END)
	{
		bEp0CsrToWrite |= SERVICED_SETUP_END;

		pContext->Ep0State = EP0_STATE_IDLE;
		pTransfer = peps->pTransfer;

		// Make MDD think everything is ok.
		if(pTransfer)
		{
			pContext->sendDataEnd = FALSE;
			CompleteTransfer(pContext, peps, UFN_NO_ERROR);
		}

		DEBUGMSG(ZONE_USB_EVENTS, (_T("Setup End %x,\r\n"),bEP0IrqStatus));
	}

	// Set By USB if protocol violation detected
	if (bEP0IrqStatus & EP0_SENT_STALL)
	{
		// Must Clear both Send and Sent Stall
		pContext->Ep0State = EP0_STATE_IDLE;
	}

	fSendUdr = FALSE;

	rINDEX_REG=0;
	cbFifo = rOUT_FIFO_CNT1_REG;
	fCompleted = FALSE;
	dwStatus;

	if (pContext->Ep0State == EP0_STATE_IDLE)
	{
		
		if (bEP0IrqStatus & EP0_OUT_PACKET_RDY)
		{
			if (pContext->fSpeedReported == FALSE)
			{
				// After Every Reset Notify MDD of Speed setting.
				// This device can only support FULL Speed.
				pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_SPEED,
				                    BS_FULL_SPEED);
				pContext->fSpeedReported = TRUE;
			}

			DEBUGMSG(1, (_T("Setup %dB,\r\n"),cbFifo));
			// New setup packet
			cbOutFifo = cbFifo;

			pbUdr = (PBYTE) &pContext->udr;

			cbBytesRemaining = cbOutFifo;
			while (cbBytesRemaining--)
			{
				*pbUdr++ = rEP0_FIFO;
			}

			
			if (cbOutFifo != sizeof(pContext->udr))
			{
				DEBUGMSG(ZONE_ERROR, (_T("Setup packet was only %x bytes!\r\n"),cbOutFifo));

				// Ideally this should not hapen. This is a recovery mechanism if
				// we get out of sync somehow.
				bEp0CsrToWrite |= (EP0_SEND_STALL | SERVICED_OUT_PKY_RDY |
				                   DATA_END);
			}
			else
			{
				//Visual: add
				//DBG_SetupReq((PBYTE) &pContext->udr);
				// Parse the Setup Command this is necessary to Configure the
				// SW State Machine and to set bits to enable the HW to
				// ACK/NAK correctly.

				// Determine if this is a NO Data Packet
				if (pContext->udr.wLength > 0)
				{
					// Determine transfer Direction
					if (pContext->udr.bmRequestType & USB_ENDPOINT_DIRECTION_MASK)
					{
						// Start the SW OUT State Machine
						pContext->Ep0State = EP0_STATE_IN_DATA_PHASE;
					}
					else
					{
						// Start the SW OUT State Machine
						pContext->Ep0State = EP0_STATE_OUT_DATA_PHASE;
					}

					pContext->sendDataEnd = FALSE;
				}
				else
				{ // udr.wLength == 0
					// ClientDriver will issue a SendControlStatusHandshake to
					// complete the transaction.
					pContext->sendDataEnd = TRUE;

					// Nothing left to do... stay in IDLE.
					DEBUGCHK(pContext->Ep0State == EP0_STATE_IDLE);
				}

				fSendUdr = TRUE;
			}
		}
	}
	else if (pContext->Ep0State == EP0_STATE_OUT_DATA_PHASE)
	{
		if (bEP0IrqStatus & OUT_PACKET_READY)
		{
			bEp0CsrToWrite |= SERVICED_OUT_PKY_RDY;

			// Check For out packet read && receive fifo not empty -> out token event
			if (cbFifo)
			{
				DEBUGMSG(ZONE_RECEIVE, (_T("%s out token packet on endpoint 0 \r\n"),
				                        pszFname));
				bEp0CsrToWrite |= HandleRx(pContext, peps, &fCompleted, &dwStatus);
			}
			// status stage of control transfer; zero-length packet received
			else
			{
				DEBUGMSG(ZONE_RECEIVE, (_T("%s status stage of control transfer on endpoint 0\r\n"),
				                        pszFname));
				pContext->Ep0State = EP0_STATE_IDLE;
			}
		}
	}
	else
	{
		DEBUGMSG(ZONE_SEND, (_T("DataPhase In %x,"),bEP0IrqStatus ));

		bHandleTx = FALSE;

		// IN Data Phase and IPR is cleared
		// Check For status stage - End control transfer; zero-length packet received
		if ( (bEP0IrqStatus &  OUT_PACKET_READY) && (cbFifo == 0) )
		{
			bHandleTx = TRUE;

			DEBUGMSG(ZONE_SEND, (_T("In - end xfer\r\n"),));
		}
		else if ((bEP0IrqStatus & EP0_IN_PACKET_RDY) == 0)
		{
			bHandleTx = TRUE;
		}

		if (bHandleTx)
		{
			bEp0CsrToWrite |= HandleTx(pContext, peps, 0);
		}
	}

	// Clear any interrupts
	rEP0_CSR=bEp0CsrToWrite;

	if (fCompleted)
	{
		CompleteTransfer(pContext, peps, dwStatus);
	}

	if (fSendUdr)
	{
		pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_SETUP_PACKET, (DWORD) &pContext->udr);
	}

}


// Process an endpoint interrupt.  Call interrupt-specific handler.
static
VOID
HandleEndpointEvent(
    PCTRLR_PDD_CONTEXT  pContext,
    DWORD               dwEndpoint,
    DWORD               epIrqStat
)
{
	DWORD dwPendingEvents = 0;
	EP_STATUS *peps = GetEpStatus(pContext, dwEndpoint);
	BOOL fCompleted = FALSE;
	DWORD dwStatus;
	BYTE bEpIrqStat;
	BYTE bEpIrqStatToWrite;
	USB_DEVICE_REQUEST udr;


	//Clear Endpoint Interrupt
	if(dwEndpoint==1)
	{
		rEP_INT_REG=EP1_INT;
	}
	else if(dwEndpoint==2)
	{
		rEP_INT_REG=EP2_INT;
	}
	else if(dwEndpoint==3)
	{
		rEP_INT_REG=EP3_INT;
	}
	else if(dwEndpoint==4)
	{
		rEP_INT_REG=EP4_INT;
	}

	rINDEX_REG=(BYTE) dwEndpoint;
	if (peps->dwDirectionAssigned == USB_IN_TRANSFER)
		bEpIrqStat=rIN_CSR1_REG;
	else
		bEpIrqStat=rOUT_CSR1_REG;

	
	if (peps->dwDirectionAssigned == USB_IN_TRANSFER)
	{
		bEpIrqStatToWrite = bEpIrqStat & (IN_SEND_STALL  | IN_SENT_STALL) &
		                    ~(IN_CLR_DATA_TOGGLE);

		// Stall "acknowledged" from Host
		if (bEpIrqStat & IN_SENT_STALL)
		{

			udr.bmRequestType = USB_REQUEST_FOR_ENDPOINT;
			udr.bRequest = USB_REQUEST_CLEAR_FEATURE;
			udr.wValue = USB_FEATURE_ENDPOINT_STALL;
			udr.wIndex = USB_ENDPOINT_DIRECTION_MASK | (BYTE) dwEndpoint;
			udr.wLength = 0;

			DisableEndpointInterrupt(pContext, dwEndpoint);

			pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_SETUP_PACKET, (DWORD) &udr);
			// Must Clear both Send and Sent Stall
			bEpIrqStatToWrite &= ~(IN_SEND_STALL  | IN_SENT_STALL);
		}

		if( !(bEpIrqStat & IN_PACKET_READY) )
		{
			bEpIrqStatToWrite |= HandleTx(pContext, peps, 0);
		}
		rIN_CSR1_REG=bEpIrqStatToWrite;
	}
	else
	{
		bEpIrqStatToWrite = bEpIrqStat & (OUT_SEND_STALL | OUT_SENT_STALL) &
		                    ~(OUT_CLR_DATA_TOGGLE);
		DEBUGMSG(ZONE_COMMENT, (_T("Ep%u OUT_CSR1_REG = 0x%x\r\n"),dwEndpoint, bEpIrqStat));

		// Stall "acknowledged" from Host
		if (bEpIrqStat & OUT_SENT_STALL)
		{
			USB_DEVICE_REQUEST udr;
			udr.bmRequestType = USB_REQUEST_FOR_ENDPOINT;
			udr.bRequest = USB_REQUEST_CLEAR_FEATURE;
			udr.wValue = USB_FEATURE_ENDPOINT_STALL;
			udr.wIndex = (USHORT) dwEndpoint;
			udr.wLength = 0;

			DisableEndpointInterrupt(pContext, dwEndpoint);

			DEBUGMSG(ZONE_PIPE, (_T("%s Got OUT_SENT_STALL EP%u \r\n"),
			                     pszFname, dwEndpoint));

			pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_SETUP_PACKET, (DWORD) &udr);
			// Must Clear both Send and Sent Stall
			bEpIrqStatToWrite &= ~(OUT_SEND_STALL | OUT_SENT_STALL);
		}

		// receive packet complete && receive fifo not empty -> out token + data rx event
		if (bEpIrqStat & OUT_PACKET_READY)
		{
			DEBUGMSG(ZONE_RECEIVE, (_T("received packet complete on endpoint %u\r\n"),
			                        peps->dwEndpointNumber));
			// the UDC combines the OUT token event with the Data RX event
			dwPendingEvents = OUT_TRANSFER;
			bEpIrqStatToWrite |= HandleRx(pContext, peps, &fCompleted, &dwStatus);
		}
		if (fCompleted)
		{
			// Disable transfer interrupts until another transfer is issued.
			DisableEndpointInterrupt(pContext, peps->dwEndpointNumber);
			CompleteTransfer(pContext, peps, dwStatus);
		}
		rOUT_CSR1_REG=bEpIrqStatToWrite;
	}


	FUNCTION_LEAVE_MSG();
}


// Process USB Bus interrupt
static
VOID
HandleUSBBusIrq(
    PCTRLR_PDD_CONTEXT  pContext,
    BYTE                bUSBBusIrqStat
)
{
	
	if (bUSBBusIrqStat & RESET_INT)
	{
		//clear interrupt
		rUSB_INT_REG= RESET_INT;

		RETAILMSG(ZONE_USB_EVENTS, (_T("Reset\r\n")));

		ResetDevice(pContext);
		pContext->fSpeedReported = FALSE;

		if (pContext->attachedState == UFN_DETACH)
		{
			pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_ATTACH);
			pContext->attachedState = UFN_ATTACH;
		}

		pContext->Ep0State = EP0_STATE_IDLE;
		pContext->pfnNotify(pContext->pvMddContext, UFN_MSG_BUS_EVENTS, UFN_RESET);

	}
	else if (bUSBBusIrqStat & SUSPEND_INT)
	{
		RETAILMSG(ZONE_USB_EVENTS, (_T("suspend,")));
		rUSB_INT_REG=SUSPEND_INT;
	}
	else if(bUSBBusIrqStat & RESUME_INT)
	{
		RETAILMSG(ZONE_USB_EVENTS, (_T("resume,")));
		rUSB_INT_REG=RESUME_INT;		
	}
}


// Process a SC2440 interrupt.
static VOID HandleUSBEvent(PCTRLR_PDD_CONTEXT pContext)
{

	DWORD dwEndpoint;
	BYTE bEpIrqStat = rEP_INT_REG;
	BYTE bUSBBusIrqStat = rUSB_INT_REG;


	//  while (bEpIrqStat || bUSBBusIrqStat) {
	if (bUSBBusIrqStat)
	{
		DEBUGMSG(ZONE_COMMENT, (_T("%s USB_INT_REG = 0x%02x\r\n"),
		                        pszFname, bUSBBusIrqStat));
		HandleUSBBusIrq(pContext, bUSBBusIrqStat);
	}

	if (bEpIrqStat)
	{
		DEBUGMSG(ZONE_COMMENT, (_T("%s EP_INT_REG = 0x%02x\r\n"),
		                        pszFname, bEpIrqStat));


		if (bEpIrqStat & EP0_INT_INTR)
		{
			//printk(_T("EP0 "));
			HandleEndpoint0Event(pContext);
		}

		// Process All Other (besides EP0) Endpoints
		for (dwEndpoint = 1; dwEndpoint < ENDPOINT_COUNT; ++dwEndpoint)
		{
			// Check the Interrupt Status
			if (bEpIrqStat & (1 << (BYTE)dwEndpoint))
			{
				//printk(_T("EP "));
				HandleEndpointEvent(pContext, dwEndpoint, bEpIrqStat);
			}

		}
	}
}

void  InterruptThread()
{
	HandleUSBEvent(&g_pdd);
	IPLIntrDoneIrq(IRQ_USBD);
}
static VOID StartTransfer(PCTRLR_PDD_CONTEXT pContext,PEP_STATUS peps,PSTransfer pTransfer)
{
	BYTE bEpIrqStat;
	BYTE bEP0IrqStatus;
	BYTE bEp0CsrToWrite;
	BYTE bEpStatToWrite;
	BOOL fCompleted;
	DWORD dwStatus;
	BYTE bIrqStatus;


	DEBUGMSG(ZONE_TRANSFER, (_T("%s tran on ep%u for %u\r\n"),
	                        (pTransfer->dwFlags == USB_IN_TRANSFER) ? _T("in") : _T("out"),
	                         peps->dwEndpointNumber, pTransfer->cbBuffer));

	// Enable transfer interrupts.
	peps->pTransfer = pTransfer;

	rINDEX_REG=(BYTE)peps->dwEndpointNumber;
	if (pTransfer->dwFlags == USB_IN_TRANSFER)
	{
		// Must Clear both Send and Sent Stall - the HW is setting this bit
		// during the Endpoint initialization process. It must be cleared here
		// to insure proper operation.
		//        SetClearIndexedReg(pContext, peps->dwEndpointNumber, IN_CSR1_REG_OFFSET,
		//            (IN_SEND_STALL | IN_SENT_STALL), CLEAR);

		if (peps->dwEndpointNumber == 0)
		{

			bEP0IrqStatus =rEP0_CSR;

			// Write 0 to SEND_STALL and SENT_STALL to clear them, so we need to
			// leave them unchanged by default.
			bEp0CsrToWrite = (bEP0IrqStatus & EP0_STALL_BITS);

			if (bEP0IrqStatus & EP0_OUT_PACKET_RDY)
			{
				bEp0CsrToWrite |= SERVICED_OUT_PKY_RDY;
				
				rEP0_CSR=bEp0CsrToWrite;
				bEp0CsrToWrite &= ~SERVICED_OUT_PKY_RDY;
			}

			bEp0CsrToWrite |= HandleTx(pContext, peps, 0);

			DEBUGMSG(ZONE_COMMENT, (_T("Wr 0x%02x to EP0_CSR_REG\r\n"), bEp0CsrToWrite));
			rEP0_CSR= bEp0CsrToWrite;
		}
		else
		{
			bIrqStatus = rIN_CSR1_REG;

			// Write 0 to SEND_STALL and SENT_STALL to clear them, so we need to
			// leave them unchanged by default.
			bEpStatToWrite = (bIrqStatus & (IN_SENT_STALL & IN_SEND_STALL));

			bEpStatToWrite |= HandleTx(pContext, peps, 1);

			DEBUGMSG(ZONE_COMMENT, (_T("Writing 0x%02x to IN_CSR1_REG\r\n"), bIrqStatus));
			rIN_CSR1_REG=bEpStatToWrite;
		}
	}
	else
	{
		if (peps->dwEndpointNumber == 0)
		{
			bEP0IrqStatus = rEP0_CSR;

			// Write 0 to SEND_STALL and SENT_STALL to clear them, so we need to
			// leave them unchanged by default.
			bEp0CsrToWrite = (bEP0IrqStatus & EP0_STALL_BITS);

			// Mark that we are done with the setup packet. The IST will take care
			// of the data transfer.
			if (bEP0IrqStatus & EP0_OUT_PACKET_RDY)
			{
				bEp0CsrToWrite |= SERVICED_OUT_PKY_RDY;
				DEBUGMSG(ZONE_COMMENT, (_T("%s Writing 0x%02x to EP0_CSR_REG\r\n"), pszFname, bEp0CsrToWrite));
				rEP0_CSR=bEp0CsrToWrite;
			}
		}
		else
		{
			EnableEndpointInterrupt(pContext, peps->dwEndpointNumber);

			// There may be a packet available.  If so process it...
			bEpIrqStat = rOUT_CSR1_REG;

			if (bEpIrqStat & OUT_PACKET_READY)
			{

				BYTE bToWrite = HandleRx(pContext, peps, &fCompleted, &dwStatus);
				DEBUGMSG(ZONE_COMMENT, (_T("%s Writing 0x%02x to OUT_CSR1_REG\r\n"), pszFname,
				                        bToWrite));

				// There should be no double-buffering
				if (fCompleted)
				{
					// Disable transfer interrupts until another transfer is issued.
					DisableEndpointInterrupt(pContext, peps->dwEndpointNumber);
				}

				rOUT_CSR1_REG=bToWrite;

				if (fCompleted)
				{
					CompleteTransfer(pContext, peps, dwStatus);
				}
			}
		}
	}

	FUNCTION_LEAVE_MSG();

}
DWORD UfnPdd_IssueTransfer(
    PVOID  pvPddContext,
    DWORD  dwEndpoint,
    PSTransfer pTransfer
)
{
	PEP_STATUS peps;
	PCTRLR_PDD_CONTEXT pContext;

	pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;

	peps = GetEpStatus(pContext, dwEndpoint);

	StartTransfer(pContext, peps, pTransfer);

	return ERROR_SUCCESS;
}


DWORD UfnPdd_AbortTransfer(
    PVOID           pvPddContext,
    DWORD           dwEndpoint,
    PSTransfer      pTransfer
)
{

	return ERROR_SUCCESS;
}


DWORD UfnPdd_Deinit(    PVOID pvPddContext)
{

	return ERROR_SUCCESS;
}


DWORD UfnPdd_Start(PVOID pvPddContext)
{
	S3C2440X_IOPORT_REG *pIOPortReg;
	// Configure port J ,PGJ9
	pIOPortReg = (S3C2440X_IOPORT_REG*)OALPAtoVA(S3C2440X_BASE_REG_PA_IOPORT, FALSE);
	SETREG32(&pIOPortReg->GPJCON, (1 << 18));
	SETREG32(&pIOPortReg->GPJUP, (1 << 9));
	//pull down
	CLRREG32(&pIOPortReg->GPJDAT, (1 << 9));
	//pull up
	SETREG32(&pIOPortReg->GPJDAT, (1 << 9));
	CLRREG32(&pIOPortReg->MISCCR, (1 << 3)|(3<<12));
	ResetDevice(pvPddContext);

	return TRUE;
}


// Stop the device.
DWORD UfnPdd_Stop(PVOID pvPddContext)
{
	S3C2440X_IOPORT_REG *pIOPortReg;
	rEP_INT_REG=EP0_INT|EP1_INT|EP2_INT|EP3_INT|EP4_INT;
	rUSB_INT_REG=RESET_INT|SUSPEND_INT|RESUME_INT;

	// Configure port J ,PGJ9,pull-up resisitor
	pIOPortReg = (S3C2440X_IOPORT_REG*)OALPAtoVA(S3C2440X_BASE_REG_PA_IOPORT, FALSE);
	SETREG32(&pIOPortReg->GPJCON, (1 << 18));
	SETREG32(&pIOPortReg->GPJUP, (1 << 9));
	CLRREG32(&pIOPortReg->GPJDAT, (1 << 9));
	return ERROR_SUCCESS;
}


DWORD UfnPdd_IsConfigurationSupportable(
    PVOID                       pvPddContext,
    UFN_BUS_SPEED               Speed,
    PUFN_CONFIGURATION          pConfiguration
)
{
	DWORD dwRet;

	dwRet = ERROR_SUCCESS;

	return dwRet;
}


//
// Is this endpoint supportable.
DWORD UfnPdd_IsEndpointSupportable(
    PVOID                       pvPddContext,
    DWORD                       dwEndpoint,
    UFN_BUS_SPEED               Speed,
    PUSB_ENDPOINT_DESCRIPTOR    pEndpointDesc,
    BYTE                        bConfigurationValue,
    BYTE                        bInterfaceNumber,
    BYTE                        bAlternateSetting
)
{



	return ERROR_SUCCESS;
}


// Clear an endpoint stall.
DWORD UfnPdd_ClearEndpointStall(
    PVOID pvPddContext,
    DWORD dwEndpoint
)
{
	DWORD dwRet = ERROR_SUCCESS;

	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;

	PEP_STATUS peps = GetEpStatus(pContext, dwEndpoint);
	SETFNAME();
	FUNCTION_ENTER_MSG();
	rINDEX_REG=dwEndpoint;
	if (dwEndpoint == 0)
	{
		// Must Clear both Send and Sent Stall
		rEP0_CSR=0;
	}
	else if (peps->dwDirectionAssigned == USB_IN_TRANSFER)
	{
		rIN_CSR1_REG|=(IN_SEND_STALL | IN_CLR_DATA_TOGGLE );

		// Must Clear both Send and Sent Stall
		rIN_CSR1_REG&=(~(IN_SEND_STALL  | IN_SENT_STALL));
	}
	else
	{ // Out Endpoint
		// Must Clear both Send and Sent Stall
		rOUT_CSR1_REG|=( OUT_SEND_STALL | OUT_CLR_DATA_TOGGLE );
		rOUT_CSR1_REG&=(~( OUT_SEND_STALL  | OUT_SENT_STALL));
	}

	FUNCTION_LEAVE_MSG();

	return ERROR_SUCCESS;
}


// Initialize an endpoint.
DWORD UfnPdd_InitEndpoint(
    PVOID                       pvPddContext,
    DWORD                       dwEndpoint,
    UFN_BUS_SPEED               Speed,
    PUSB_ENDPOINT_DESCRIPTOR    pEndpointDesc,
    PVOID                       pvReserved,
    BYTE                        bConfigurationValue,
    BYTE                        bInterfaceNumber,
    BYTE                        bAlternateSetting
)
{
	return ERROR_SUCCESS;
}


// Deinitialize an endpoint.
DWORD UfnPdd_DeinitEndpoint(
    PVOID pvPddContext,
    DWORD dwEndpoint
)
{
	return ERROR_SUCCESS;
}


// Stall an endpoint.
DWORD UfnPdd_StallEndpoint(
    PVOID pvPddContext,
    DWORD dwEndpoint
)
{
	DWORD dwRet = ERROR_SUCCESS;


	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;

	PEP_STATUS peps = GetEpStatus(pContext, dwEndpoint);
	SETFNAME();
	FUNCTION_ENTER_MSG();
	rINDEX_REG=dwEndpoint;

	if (dwEndpoint == 0)
	{
		// Must Clear Out Packet Ready when sending Stall
		BYTE bEp0StallBits = (DATA_END | SERVICED_OUT_PKY_RDY | EP0_SEND_STALL);
		DEBUGMSG(ZONE_SEND, (_T("%s Writing 0x%02x to EP0_CSR_REG\r\n"), pszFname,
		                     bEp0StallBits));
		rEP0_CSR=bEp0StallBits;
		// Set Flag so that SendControlStatusHandshked does not
		// duplicate this HW Write. Manual says all bits need
		// to be set at the same time.
		pContext->sendDataEnd = FALSE;
		pContext->Ep0State = EP0_STATE_IDLE;
	}
	else if (peps->dwDirectionAssigned == USB_IN_TRANSFER)
	{
		rIN_CSR1_REG|=(IN_SEND_STALL);
	}
	else
	{ // Out Endpoint
		// Must Clear Out Packet Ready when sending Stall
		rOUT_CSR1_REG|=(OUT_SEND_STALL);
		rOUT_CSR1_REG&=(~OUT_PACKET_READY);
	}

	FUNCTION_LEAVE_MSG();

	return ERROR_SUCCESS;
}


// Send the control status handshake.
DWORD UfnPdd_SendControlStatusHandshake(
    PVOID           pvPddContext,
    DWORD           dwEndpoint
)
{


	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;
	BYTE bEP0IrqStatus;
	BYTE bEp0CsrToWrite;
	// This function is only valid for Endpoint 0
	EP_STATUS *peps = GetEpStatus(pContext, 0);
	SETFNAME();
	FUNCTION_ENTER_MSG();

	// Remove the Out Packet Ready Condition
	if(pContext->sendDataEnd)
	{
		DEBUGMSG(ZONE_SEND, (_T("%s Sending 0 packet \r\n"), pszFname));

		rINDEX_REG=0;
		bEP0IrqStatus = rEP0_CSR;

		// Write 0 to SEND_STALL and SENT_STALL to clear them, so we need to
		// leave them unchanged by default.
		bEp0CsrToWrite = (bEP0IrqStatus & EP0_STALL_BITS);

		bEp0CsrToWrite |= (DATA_END | SERVICED_OUT_PKY_RDY);

		DEBUGMSG(ZONE_SEND, (_T("%s Status - 0x%02x, Writing 0x%02x\r\n"), pszFname,
		                     bEP0IrqStatus, bEp0CsrToWrite));

		rEP0_CSR=bEp0CsrToWrite;

		pContext->sendDataEnd = FALSE;
	}

	FUNCTION_LEAVE_MSG();

	return ERROR_SUCCESS;
}


// Set the address of the device on the USB.
DWORD UfnPdd_SetAddress(
    PVOID pvPddContext,
    BYTE  bAddress
)
{
	// Make sure that the Address Update bit is set (0x80)
	rFUNC_ADDR_REG=(0x80 | bAddress);

	return ERROR_SUCCESS;
}


// Is endpoint Stalled?
DWORD UfnPdd_IsEndpointHalted(
    PVOID pvPddContext,
    DWORD dwEndpoint,
    PBOOL pfHalted
)
{
	return FALSE;
}


DWORD UfnPdd_InitiateRemoteWakeup(
    PVOID pvPddContext
)
{

	return ERROR_SUCCESS;
}


DWORD UfnPdd_RegisterDevice(
    PVOID                           pvPddContext,
    PCUSB_DEVICE_DESCRIPTOR         pHighSpeedDeviceDesc,
    PCUFN_CONFIGURATION             pHighSpeedConfig,
    PCUSB_CONFIGURATION_DESCRIPTOR  pHighSpeedConfigDesc,
    PCUSB_DEVICE_DESCRIPTOR         pFullSpeedDeviceDesc,
    PCUFN_CONFIGURATION             pFullSpeedConfig,
    PCUSB_CONFIGURATION_DESCRIPTOR  pFullSpeedConfigDesc,
    PCUFN_STRING_SET                pStringSets,
    DWORD                           cStringSets
)
{
	PCTRLR_PDD_CONTEXT pContext = (PCTRLR_PDD_CONTEXT) pvPddContext;

	DEBUGMSG(1,(_T("UfnPdd_RegisterDevice\r\n \r\n")));

	// Nothing to do.

	return ERROR_SUCCESS;
}


DWORD UfnPdd_DeregisterDevice(
    PVOID   pvPddContext
)
{
	return ERROR_SUCCESS;
}


VOID UfnPdd_PowerDown(
    PVOID pvPddContext
)
{}


VOID UfnPdd_PowerUp(
    PVOID pvPddContext
)
{}


DWORD UfnPdd_IOControl(
    PVOID           pvPddContext,
    IOCTL_SOURCE    source,
    DWORD           dwCode,
    PBYTE           pbIn,
    DWORD           cbIn,
    PBYTE           pbOut,
    DWORD           cbOut,
    PDWORD          pcbActualOut
)
{
	return TRUE;
}

// Initialize the device.
DWORD 	UfnPdd_Init(
    LPCTSTR                     pszActiveKey,
    PVOID                       pvMddContext,
    PUFN_MDD_INTERFACE_INFO     pMddInterfaceInfo,
    PUFN_PDD_INTERFACE_INFO     pPddInterfaceInfo
)
{
	PCTRLR_PDD_CONTEXT pContext = NULL;
	DWORD dwEp;
	static const UFN_PDD_INTERFACE_INFO sc_PddInterfaceInfo =
	    {
	        UFN_PDD_INTERFACE_VERSION,
	        UFN_PDD_CAPS_SUPPORTS_FULL_SPEED,
	        ENDPOINT_COUNT,
	        NULL, // This gets filled in later
	        &UfnPdd_Deinit,
	        &UfnPdd_IsConfigurationSupportable,
	        &UfnPdd_IsEndpointSupportable,
	        &UfnPdd_InitEndpoint,
	        &UfnPdd_RegisterDevice,
	        &UfnPdd_DeregisterDevice,
	        &UfnPdd_Start,
	        &UfnPdd_Stop,
	        &UfnPdd_IssueTransfer,
	        &UfnPdd_AbortTransfer,
	        &UfnPdd_DeinitEndpoint,
	        &UfnPdd_StallEndpoint,
	        &UfnPdd_ClearEndpointStall,
	        &UfnPdd_SendControlStatusHandshake,
	        &UfnPdd_SetAddress,
	        &UfnPdd_IsEndpointHalted,
	        &UfnPdd_InitiateRemoteWakeup,
	        &UfnPdd_PowerDown,
	        &UfnPdd_PowerUp,
	        &UfnPdd_IOControl,
	    };

	pContext=&g_pdd;

	memset(pContext, 0, sizeof(g_pdd));
	pContext->pvMddContext = pvMddContext;
	pContext->pfnNotify = pMddInterfaceInfo->pfnNotify;
	memcpy(pPddInterfaceInfo, &sc_PddInterfaceInfo, sizeof(sc_PddInterfaceInfo));
	pPddInterfaceInfo->pvPddContext = pContext;

	for (dwEp = 0; dwEp < dim(pContext->rgEpStatus); ++dwEp)
	{
		pContext->rgEpStatus[dwEp].dwEndpointNumber = dwEp;
	}
	
	IPLIntrRequestIrq(IRQ_USBD,InterruptThread);
	IPLIntrEnableIrq(IRQ_USBD);
	return ERROR_SUCCESS ;
}




